package com.doge.calcalbum.utils

import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.graphics.Bitmap
import android.graphics.Color
import android.util.LruCache
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import androidx.annotation.IdRes
import androidx.collection.ArrayMap
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.Transformation
import com.bumptech.glide.request.RequestOptions
import com.github.iielse.imageviewer.utils.Config
import io.reactivex.Observable
import jp.wasabeef.glide.transformations.RoundedCornersTransformation
import java.util.concurrent.TimeUnit


//private var sbh: Int? = null
//val statusBarHeight: Int
//    get() {
//        val cache = sbh
//        if (cache != null) return cache
//
//        var height = 0
//        val resourceId = appContext.resources.getIdentifier("status_bar_height", "dimen", "android")
//        if (resourceId > 0) {
//            height = appContext.resources.getDimensionPixelSize(resourceId)
//        }
//        return height.also { sbh = it }
//    }

val systemWindowInsetsTop = MutableLiveData<Int>() // for home page
fun updateSystemWindowInsetsTop(value: Int) {
    if (systemWindowInsetsTop.value != value) systemWindowInsetsTop.value = value

    Config.TRANSITION_OFFSET_Y = value // viewer
}

fun View.setOnClickCallback(interval: Long = 300L, callback: (View) -> Unit) {
    if (!isClickable) isClickable = true
    if (!isFocusable) isFocusable = true
    Observable.create<View> {
        setOnClickListener(it::onNext)
    }.throttleFirst(interval, TimeUnit.MILLISECONDS)
        .doOnNext { callback(this) }
        .subscribe()
}

fun Activity.closeKeyBoard(): Boolean {
    val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
    return imm?.hideSoftInputFromWindow(window.decorView.applicationWindowToken, 0) ?: false
}

fun Fragment.closeKeyBoard(): Boolean {
    val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
    val token = view?.applicationWindowToken ?: return false
    return imm?.hideSoftInputFromWindow(token, 0) ?: false
}

fun ViewGroup.inflate(resId: Int): View {
    return LayoutInflater.from(context).inflate(resId, this, false)
}

val View.activity: Activity?
    get() = getActivity(context) ?: Activities.top

val View.lifecycleOwner: LifecycleOwner?
    get() {
        val activity = activity as? FragmentActivity? ?: return null
        val fragment = findSupportFragment(this, activity)
        return fragment?.viewLifecycleOwner ?: activity
    }

private val tempViewToSupportFragment = ArrayMap<View, Fragment>()
private fun findSupportFragment(target: View, activity: FragmentActivity): Fragment? {
    tempViewToSupportFragment.clear()
    findAllSupportFragmentsWithViews(
        activity.supportFragmentManager.fragments, tempViewToSupportFragment
    )
    var result: Fragment? = null
    val activityRoot = activity.findViewById<View>(android.R.id.content)
    var current = target
    while (current != activityRoot) {
        result = tempViewToSupportFragment[current]
        if (result != null) {
            break
        }
        current = if (current.parent is View) {
            current.parent as View
        } else {
            break
        }
    }
    tempViewToSupportFragment.clear()
    return result
}

private fun findAllSupportFragmentsWithViews(
    topLevelFragments: Collection<Fragment?>?, result: MutableMap<View?, Fragment>
) {
    if (topLevelFragments == null) {
        return
    }
    for (fragment in topLevelFragments) {
        // getFragment()s in the support FragmentManager may contain null values, see #1991.
        if (fragment?.view == null) {
            continue
        }
        result[fragment.view] = fragment
        findAllSupportFragmentsWithViews(fragment.childFragmentManager.fragments, result)
    }
}

// https://stackoverflow.com/questions/9273218/is-it-always-safe-to-cast-context-to-activity-within-view/45364110
private fun getActivity(context: Context?): Activity? {
    if (context == null) return null
    if (context is Activity) return context
    if (context is ContextWrapper) return getActivity(context.baseContext)
    return null
}

fun <T : View> RecyclerView.ViewHolder.find(@IdRes id: Int): T? = itemView.findViewById(id)

//fun TabLayout.setupWithViewPager2(viewPager2: ViewPager2) {
//    TabLayoutMediator(
//        this, viewPager2, true
//    ) { tab, position ->
//        val title = (viewPager2.adapter as FragmentStateAdapter).getTitle(position)
//        tab.text = title
//    }.attach()
//}

val RoundedCorners4 by lazy { RoundedCornersTransformation(4.dp, 0) }
val RoundedCorners12 by lazy { RoundedCornersTransformation(12.dp, 0) }

fun ImageView.load(
    url: String?,
    placeHolder: Int? = null,
    transformation: Transformation<Bitmap>? = null,
    width: Int? = null,
    height: Int? = null,
    type: Int? = 8,
    quality: Int = 75,
) {
    val thumbnail = if (type != null && (width != null || height != null)) {
        thumbnail(url, width ?: 0, height ?: 0, type, quality)
    } else url
    load(thumbnail, placeHolder, transformation)
}

private fun ImageView.load(
    url: String?, placeHolder: Int? = null,
    transformation: Transformation<Bitmap>? = null
) {
    log("image load $url")
    if (url.isNullOrEmpty()) {
        setImageResource(placeHolder ?: android.R.color.transparent)
        return
    }

    var requestOptions = RequestOptions()
    if (placeHolder != null) {
        requestOptions = (requestOptions)
            .placeholder(placeHolder)
            .error(placeHolder)
    }
    if (transformation != null) {
        requestOptions = (requestOptions)
            .transform(transformation)
    }
    Glide.with(this).load(url)
        .apply(requestOptions)
        .into(this)
}


val screenWidth by lazy { appContext.resources.displayMetrics.widthPixels }
//val screenHeight by lazy { appContext.resources.displayMetrics.heightPixels }

private val dps by lazy { LruCache<Int, Int>(100) }
val Int.dp: Int get() = dp(this)
fun View.dp(value: Int) = dp(value, context)

private fun dp(value: Int, context: Context? = null): Int {
    val result = dps[value]
    if (result != null && result >= 0) return result
    return TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        value.toFloat(),
        (context ?: appContext).resources.displayMetrics
    ).toInt().also {
        dps.put(value, it)
    }
}

//fun getDrawable(drawableRes: Int, scale: Float = 1F): Drawable? {
//    val drawable = ContextCompat.getDrawable(appContext, drawableRes)
//    drawable?.setBounds(
//        0,
//        0,
//        (drawable.minimumWidth * scale).toInt(),
//        (drawable.minimumHeight * scale).toInt()
//    )
//    return drawable
//}

fun getString(id: Int): String = appContext.getString(id)

private val colors by lazy { mutableMapOf<String, Int>() }
fun getColor(color: String): Int {
    val result = colors[color]
    if (result != null) return result
    return try {
        Color.parseColor(color).also { colors[color] = it }
    } catch (e: Exception) {
        e.printStackTrace()
        Color.TRANSPARENT
    }
}
